/*
 * FormaPiedra.cpp
 *
 *  Created on: 22/10/2013
 *      Author: ezequiel
 */
#define CANT_PUNTOS 15
#define ALTURA 30
#include "FormaPiedra.h"

FormaPiedra::FormaPiedra() {
	this->piedra_vertex_buffer_size = (CANT_PUNTOS) * 6 * ALTURA;
		    this->piedra_vertex_buffer = new GLfloat[this->piedra_vertex_buffer_size];
		    this->piedra_texture_buffer = new GLfloat[this->piedra_vertex_buffer_size * 2 / 3 ];
		    this->piedra_normal_buffer_size = (CANT_PUNTOS) * 6 * ALTURA ;
		    this->piedra_normal_buffer = new GLfloat[this->piedra_normal_buffer_size];
		    this->piedra_index_buffer_size = 1745;
		    this->piedra_index_buffer = new GLuint[this->piedra_index_buffer_size];
//		    this->tipoTexture = GL_TEXTURE0;
//		    this->textureid = 1;
//		    this->loadAndInitTexture("imagen.bmp");
		    this->crearForma();
}

FormaPiedra::~FormaPiedra() {
	delete this->piedra_vertex_buffer;
	delete this->piedra_index_buffer;
	delete this->piedra_normal_buffer;
	delete this->piedra_texture_buffer;

}

void FormaPiedra::render(GLuint handle, glm::mat4* matModelo) {
	glBindTexture (GL_TEXTURE_2D, this->textureid);
	 glm::mat3 normal_matrix = glm::mat3 ( 1.0f );

				    // Bind Normal MAtrix
				    GLuint location_normal_matrix = glGetUniformLocation(handle, "NormalMatrix");
				    if( location_normal_matrix >= 0 )
					{
				        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]);
					}

				    // Bind Model Matrix
				    GLuint location_model_matrix = glGetUniformLocation( handle, "ModelMatrix");
				    if( location_model_matrix >= 0 )
					{
						glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE,&((*matModelo)[0][0]));
					}
				    int loc = glGetUniformLocation(handle, "Tex1");
				    if( loc >= 0 )
				    {
						// We indicate that Uniform Variable sampler2D "text" uses  Texture Unit 0
				        glUniform1i(loc, 0);
				    }
				    else
				    {
				        fprintf(stderr, "Uniform variable Tex1 not found!\n");
				    }
		//		    glClearColor(20,20,0,0);
				    glEnableClientState(GL_VERTEX_ARRAY);
					glEnableClientState(GL_NORMAL_ARRAY);
					glEnableClientState(GL_TEXTURE_COORD_ARRAY);
					glVertexPointer(3, GL_FLOAT, 0,piedra_vertex_buffer);
					glNormalPointer(GL_FLOAT, 0, piedra_normal_buffer);
					glTexCoordPointer(2, GL_FLOAT, 0, piedra_texture_buffer);
				    glDrawElements(GL_TRIANGLE_STRIP, this->piedra_index_buffer_size, GL_UNSIGNED_INT, this->piedra_index_buffer);
				    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
				    glDisableClientState(GL_VERTEX_ARRAY);
				    glDisableClientState(GL_NORMAL_ARRAY);
}

void FormaPiedra::render(GLuint handle) {
}

void FormaPiedra::indexar() {
	int e = 0;
for (int k = 0 ; k < CANT_PUNTOS ; k++){
	for (int i = 2 * k * CANT_PUNTOS  ; i < 2 *k * CANT_PUNTOS + 2* CANT_PUNTOS ; i = i + 2 )
	{
		this->piedra_index_buffer[i] = e ;
		e++;
		this->piedra_index_buffer[i+1] = e + 2*CANT_PUNTOS;
		e++;

	}
}
}



glm::vec3 FormaPiedra::calcularNormal(glm::vec3 vec1, glm::vec3 vec2) {
	glm::vec3 retorno;
	retorno.x = vec1.y * vec2.z - vec1.z * vec2.y;
	retorno.y = vec1.z * vec2.x - vec1.x * vec2.z;
	retorno.z =vec1.x * vec2.y - vec1.y * vec2.x;


	return retorno;

}

void FormaPiedra::crearForma() {
	glm::vec3 vect;
		CurvaBessier* curvaS;
		std::vector<glm::vec3> curvaA;
		std::vector<glm::vec3> curvaB;
		std::vector <glm::vec3> curvaZ;
		//////// curva de forma A  ///////


		vect = glm::vec3(0.0f, 0.0f , 0.0f);
		curvaA.push_back(vect);
		vect = glm::vec3(20.0f, 30.0f , 0.0f);
		curvaA.push_back(vect);
		vect = glm::vec3(40.0f, 30.0f, 0.0f);
		curvaA.push_back(vect);
		vect = glm::vec3(60.0f, 0.0f , 0.0f);
		curvaA.push_back(vect);
		curvaS = new CurvaBessier(curvaA, CANT_PUNTOS );
		curvaA = curvaS->obtenerPuntos();
		delete curvaS;

		//////// curva de forma B  ///////
		vect = glm::vec3(60.0f, 0.0f , 0.0f);
		curvaB.push_back(vect);
		vect = glm::vec3(40.0f, -30.0f , 0.0f);
		curvaB.push_back(vect);
		vect = glm::vec3(20.0f, -30.0f, 0.0f);
		curvaB.push_back(vect);
		vect = glm::vec3(0.0f, 0.0f , 0.0f);
		curvaB.push_back(vect);
		curvaS = new CurvaBessier(curvaB, CANT_PUNTOS );
		curvaB = curvaS->obtenerPuntos();
		delete curvaS;



		//////////// curva en z ///////////////

		vect = glm::vec3(0.0f, 0.0f , 0.0f);
			curvaZ.push_back(vect);
			vect = glm::vec3(0.0f, 0.0f , 15.0f);
			curvaZ.push_back(vect);
			vect = glm::vec3(0.0f, 0.0f, 30.0f);
			curvaZ.push_back(vect);
			vect = glm::vec3(0.0f, 0.0f , 45.0f);
			curvaZ.push_back(vect);
			curvaS = new CurvaBessier(curvaZ, ALTURA );
			curvaZ = curvaS->obtenerPuntos();
			delete curvaS;

		//////////// curva grosor ////////////////////

			std::vector<glm::vec3> vecGrosor;
	    	vect = glm::vec3(0.00f, 5.0f , 0.0f);
	    	vecGrosor.push_back(vect);
	    	vect = glm::vec3(0.550f, 10.0f , 0.0f);
	    	vecGrosor.push_back(vect);
	    	vect = glm::vec3(0.950f, 15.0 , 0.0f);
	    	vecGrosor.push_back(vect);
	    	vect = glm::vec3(0.00f, 20.0f , 0.0f);
	    	vecGrosor.push_back(vect);
	    	CurvaBessier* curvaGrosor = new CurvaBessier(vecGrosor,CANT_PUNTOS - 1 );
	    	vecGrosor = curvaGrosor->obtenerPuntos();
	    	delete curvaGrosor;

		////////////// vertices, normales e indices ///////////////

		/* variables */
	    float pasoU = 0;
	    float pasoV = 0;
		int j, i , k, z, p;
		p = 0 ;
		for (z= 0; z < ALTURA; z++){
		j= 0;
				    	for( i = 6 * CANT_PUNTOS * z  ;i <  3  * CANT_PUNTOS + 6 * CANT_PUNTOS * z; i = i + 3)
				    		pasoU = 0;
				    	    pasoV = pasoV + 0.035;
				    		    	{
				    		    		this->piedra_vertex_buffer[i] = curvaA[j].x * vecGrosor[z].x   + curvaZ[z].x   ;
				    		    		this->piedra_vertex_buffer[i+1] = ( curvaA[j].y* vecGrosor[z].x   + curvaZ[z].y    )  ;
				    		    		this->piedra_vertex_buffer[i+2] = (curvaA[j].z  + curvaZ[z].z  )  ;
				    		    		this->piedra_texture_buffer[p] = pasoU;
				    		    		p++;
				    		    		this->piedra_texture_buffer[p] = pasoV;
				    		    		p++;
				    		    		pasoU = pasoU + 0.035 ;
//				    		    		this->piedra_normal_buffer[i] = 0.15f;
//				    		    		this->piedra_normal_buffer[i+1] = 0.15f;
//				    		    		this->piedra_normal_buffer[i+2] = 0.15f;
//				    		    			    		this->piedra_index_buffer[i] = j + 2 * z * CANT_PUNTOS;
//				    		    			    		this->piedra_index_buffer[i+1] = j + 2 * z * CANT_PUNTOS;
//				    		    			    		this->piedra_index_buffer[i+2] = j + 2 *  z * CANT_PUNTOS;
				    		    			    		j++;
				    		    	}
		//	}


				    	 k = j;
				    	 j= 0;
		//		for (int z = 0 ; z < ALTURA ; z++  ){
				    		    	for( i = 3 * CANT_PUNTOS +  6 * CANT_PUNTOS * z ;i < 6 * CANT_PUNTOS + z * CANT_PUNTOS * 6; i = i + 3)
				    		    		    {
				    		    		    	this->piedra_vertex_buffer[i] = (curvaB[j].x * vecGrosor[z].x  + curvaZ[z].x )      ;
				    		    		    	this->piedra_vertex_buffer[i+1] = ( curvaB[j].y * vecGrosor[z].x  + curvaZ[z].y  )     ;
				    		    		    	this->piedra_vertex_buffer[i+2] = (curvaB[j].z  + curvaZ[z].z  )  ;
						    		    		this->piedra_texture_buffer[p] = pasoU;
						    		    		p++;
						    		    		this->piedra_texture_buffer[p] = pasoV;
						    		    		p++;
						    		    		pasoU = pasoU + 0.035 ;
//				    		    		    	this->piedra_normal_buffer[i] = 0.15f;
//				    		    		    	this->piedra_normal_buffer[i+1] = 0.15f;
//				    		    		    	this->piedra_normal_buffer[i+2] = 0.15f;
//				    		    		    	this->piedra_index_buffer[i] = k + 2 *z *CANT_PUNTOS;
//				    		    		    	this->piedra_index_buffer[i+1] = k + 2 *z * CANT_PUNTOS ;
//				    		    		    	this->piedra_index_buffer[i+2] = k + 2 * z * CANT_PUNTOS;
				    		    		    			    		j++;
				    		    		    			    		k++;
				    		    		    	}

		}
		cout << "a" <<  piedra_texture_buffer[24] << " "<< piedra_texture_buffer[25] << endl;
//this->indexar();
		this->indexarForma();
		this->calcularNormales();
}

void FormaPiedra::indexarForma()
{

		int malla[30][30];

			        int e = 0;
			        for(int m = 0; m < 30; m++)
			                for(int n = 0; n < 30; n++)
			                        malla[m][n] = e++;


			        int sentido = 1;
			        int k = 0;

			        for(int i=0; i < (29); i++)
			        {
			                if(sentido == 1)
			                {
			                        for(int j=0; j <= (29); j++) {
			                                this->piedra_index_buffer[k++] = malla[i][j];
			                                this->piedra_index_buffer[k++] = malla[i+1][j];
			                        }

			                        sentido = -1;
			                }
			                else if(sentido == -1)
			                {
			                        for(int j=(29); j >= 0; j--) {
			                                this->piedra_index_buffer[k++] = malla[i][j];
			                                this->piedra_index_buffer[k++] = malla[i+1][j];
			                        }

			                        sentido = 1;
			                }
			        }

		        }

void FormaPiedra::calcularNormales()
{
	glm::vec3 vecResult;
		glm::vec3 vec1;
		glm::vec3 vec2;

	for (int k = 0 ; k < CANT_PUNTOS ; k++){
		for (int i = k * CANT_PUNTOS * 6 ; i < k * CANT_PUNTOS * 6 + CANT_PUNTOS * 6 ; i = i +3 )
		{
			vec1.x = piedra_vertex_buffer[i] - piedra_vertex_buffer[i+6*CANT_PUNTOS];
			vec1.y = piedra_vertex_buffer[i+1] - piedra_vertex_buffer[i+6*CANT_PUNTOS+1];
			vec1.z = piedra_vertex_buffer[i+2] - piedra_vertex_buffer[i+6*CANT_PUNTOS+2];
			vec2.x = piedra_vertex_buffer[i] - piedra_vertex_buffer[i+3];
			vec2.y = piedra_vertex_buffer[i+1] -piedra_vertex_buffer[i+4];
			vec2.z = piedra_vertex_buffer[i+2] -piedra_vertex_buffer[i+5];
			vecResult = calcularNormal(vec1, vec2);
			piedra_normal_buffer[i] = vecResult.x;
			piedra_normal_buffer[i+1] = vecResult.y;
			piedra_normal_buffer[i+2] = vecResult.z;

		}
	}

}

